import * as PIXI from 'pixi.js';
import { debounce } from 'lodash';
import { pb } from '../pb';
import MsgService from './msg-service';
import ImagesService from './images-service';
import { environment } from '../environments/environment.dev';
import { DISPLAY, PAGE, BLOCK, WEB } from './msg-code';
import Page from './page';
import ReconnectingWebSocket from 'reconnecting-websocket';
import { Event } from 'reconnecting-websocket';
import Card from './card';
import Images from './images';
import Web from './web';

export default class Display {
  private ws: ReconnectingWebSocket;
  private ms: MsgService;
  private is: ImagesService;
  private app: PIXI.Application;
  private id = environment.id;
  private data: pb.IDisplay;
  pages: Page[];
  images = new Map<number, Images>();
  webs = new Map<number, Web>();
  constructor() {
    PIXI.utils.sayHello(`DS: ${this.id} ${PIXI.utils.isWebGLSupported() ? 'WebGL' : 'Canvas'}`);
    this.app = new PIXI.Application({
      antialias: true,
      resizeTo: window,
      backgroundColor: 0,
    });
    this.ms = new MsgService(this.app.ticker)
    this.is = new ImagesService(this.ms);
    this.app.renderer.on('resize', debounce(() => this.reset(), 300))
    document.body.appendChild(this.app.view);
    // 键盘操作
    window.addEventListener("keyup", (ev) => this.keyup(ev), false);
  }
  get ticker() {
    return this.app.ticker;
  }
  run() {
    this.ws = new ReconnectingWebSocket(`ws://${environment.host}/ws`);
    this.ws.onopen = (ev) => this.onopen(ev);
    this.ws.onclose = (ev) => this.onclose(ev);
    this.ws.onmessage = (ev) => this.onmessage(ev);
    this.ws.onerror = (ev) => this.onerror(ev);
  }
  private async reset() {
    this.app.stage.removeChildren();
    // 显示屏背景
    if (this.data.backgroundColor) {
      this.app.renderer.backgroundColor = this.data.backgroundColor;
    }
    if (this.data.backgroundUrl) {
      this.ms.toast(`加载显示屏 ${this.data.id} 背景: ${this.data.backgroundUrl}`)
      const s = await this.is.getSprite(this.data.backgroundUrl);
      s.width = this.app.renderer.width;
      s.height = this.app.renderer.height;
      this.app.stage.addChild(s);
    }
    // 各页面
    for (const p of this.pages) {
      await p.reset(this.app.renderer.width, this.app.renderer.height);
      this.app.stage.addChild(p.container);
      this.ms.toast(`加载页面: ${p.data.id}`)
    }
    // 提示信息
    this.app.stage.addChild(this.ms.container);
  }
  // 接收消息
  private async onMsg(msg: pb.Msg) {
    this.ms.toast(`接收消息: ${msg.code}`);
    switch (msg.code) {
      // 显示
      case DISPLAY:
        this.data = msg.display;
        this.pages = [];
        for (const p of this.data.pages) {
          this.pages.push(new Page(p, this.is, this));
        }
        // 有页面则显示第一个页面
        if (this.pages.length) {
          Card.home(this.pages, this.app.ticker)
        }
        await this.reset();
        // 获取数据
        this.webs.forEach((web, id) => {
          const m = pb.Msg.create({
            // 请求数据
            code: WEB,
            id,
          })
          this.ws.send(pb.Msg.encode(m).finish());
        })
        break;
      case WEB:
        if (msg.web && msg.web.image) {
          const web = this.webs.get(msg.web.id);
          web.sprite = new PIXI.Sprite(PIXI.Texture.fromBuffer(msg.web.image, msg.web.width, msg.web.height))
          web.reset()
        }
        break;
      case PAGE:
        break;
      // 区块数据
      case BLOCK:
        // TODO容器处理
        switch (msg.block.type) {
          case pb.Block.Type.IMAGES:
            const s = await this.is.getSprite(msg.block.images.urls[0])
            s.width = this.app.view.width;
            s.height = this.app.view.height;
            this.app.stage.addChildAt(s, 0)
            // this.app.stage.addChild(s)
            this.ms.toast('加载图片')
            break;
          case pb.Block.Type.WEB:
            this.ms.toast('加载网页')
            break;
          default:
            break;
        }
        break;
    }
  }
  // 开启
  private onopen(ev: Event) {
    this.ms.toast('网络连接')
    const id = parseInt(this.id, 0);
    if (isNaN(id)) {
      this.ms.error(`错误的显示屏: ${this.id}`);
      return;
    }
    const m = pb.Msg.create({
      // 请求数据
      code: DISPLAY,
      id,
    })
    this.ws.send(pb.Msg.encode(m).finish());
    this.ms.toast(`加载数据: ${this.id}`);
    this.ms.close('网络异常', '链接关闭')
  }
  // 错误
  private onerror(ev: Event) {
    this.ms.error('网络异常')
  }
  // 收到消息
  private onmessage(ev: MessageEvent) {
    const reader = new FileReader();
    reader.onload = (e) => {
      this.ms.toast('数据接收');
      const buf = new Uint8Array(e.target.result as ArrayBuffer);
      const m = pb.Msg.decode(buf) as any;
      this.onMsg(m);
    }
    reader.readAsArrayBuffer(ev.data);
  }
  // 关闭连接
  private onclose(ev: Event) {
    this.ms.error('链接关闭');
  }
  // 键盘操作
  private keyup(ev: KeyboardEvent) {
    if (this.data.pages && this.data.pages.length) {
      switch (ev.code) {
        case 'Home':
          Card.home(this.pages, this.app.ticker)
          break;
        case 'End':
          Card.end(this.pages, this.app.ticker)
          break;
        case 'PageUp':
        case 'ArrowLeft':
        case 'ArrowUp':
          Card.up(this.pages, this.app.ticker)
          break;
        case 'PageDown':
        case 'ArrowRight':
        case 'ArrowDown':
          Card.down(this.pages, this.app.ticker)
          break;
      }
    }
  }
}
